package ws

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"github.com/gorilla/websocket"
	"intranetWs/util"
	"log"
	"net/http"
	"strconv"
	"sync"
	"time"
)

/*
自定义协议:
// 		Id, Group, Content string
// auth
{"cmd":"clients"} // 客户端列表
{"cmd":"clients","data":{"id":"..."}} // 客户端信息

// 全局 global 全屏，还原
{"cmd":"g","data":{"id":"...","group":"...", "content": "..."}, "event": "lock"} // 锁屏
{"cmd":"g","data":{"id":"...","group":"...", "content": "..."}, "event": "unlock"} // 解锁
{"cmd":"g","data":{"id":"...","group":"...", "content": "..."}, "event": "file-focus"} // 焦点
{"cmd":"g","data":{"id":"...","group":"...", "content": "..."}, "event": "open"} // 打开
{"cmd":"g","data":{"id":"...","group":"...", "content": "..."}, "event": "open-finish"} // 打开完成
{"cmd":"g","data":{"id":"...","group":"...", "content": "..."}, "event": "close"} // 关闭
{"cmd":"g","data":{"id":"...","group":"...", "content": "..."}, "event": "volume"} // 音量
{"cmd":"g","data":{"id":"...","group":"...", "content": "..."}, "event": "mute"} // 静音
{"cmd":"g","data":{"id":"...","group":"...", "content": "..."}, "event": "unmute"} // 解除静音

// 白板发送
{"cmd":"wb","data":{"id":"...","group":"...", "content": "..."}, "event": "sync"}
{"cmd":"wb","data":{"id":"...","group":"...", "content": "..."}, "event": "offline"}
{"cmd":"wb","data":{"id":"...","group":"...", "content": "..."}, "event": "online"}
{"cmd":"wb","data":{"id":"...","group":"...", "content": "..."}, "event": "open"} // 打开
{"cmd":"wb","data":{"id":"...","group":"...", "content": "..."}, "event": "close"} // 关闭

// 白板接收
...
// PPT
{"cmd":"ppt","data":{"id":"...","group":"...", "content": "..."}, "event": "next-page"}
{"cmd":"ppt","data":{"id":"...","group":"...", "content": "..."}, "event": "pre-page"}
{"cmd":"ppt","data":{"id":"...","group":"...", "content": "..."}, "event": "next-step"}
{"cmd":"ppt","data":{"id":"...","group":"...", "content": "..."}, "event": "pre-step"}
{"cmd":"ppt","data":{"id":"...","group":"...", "content": "..."}, "event": "jump"}
{"cmd":"ppt","data":{"id":"...","group":"...", "content": "..."}, "event": "ppt-media-play"}
{"cmd":"ppt","data":{"id":"...","group":"...", "content": "..."}, "event": "ppt-media-pause"}
{"cmd":"ppt","data":{"id":"...","group":"...", "content": "..."}, "event": "ppt-media-jump"}
// PDF
{"cmd":"pdf","data":{"id":"...","group":"...", "content": "..."}, "event": "open"} // 打开
{"cmd":"pdf","data":{"id":"...","group":"...", "content": "..."}, "event": "open-finish"} // 打开完成
{"cmd":"pdf","data":{"id":"...","group":"...", "content": "..."}, "event": "jump"} // 跳转
{"cmd":"pdf","data":{"id":"...","group":"...", "content": "..."}, "event": "roll"} // 滚动
{"cmd":"pdf","data":{"id":"...","group":"...", "content": "..."}, "event": "zoom"} // 缩放
{"cmd":"pdf","data":{"id":"...","group":"...", "content": "..."}, "event": "move"} // 移动
{"cmd":"pdf","data":{"id":"...","group":"...", "content": "..."}, "event": "size"} // 窗口大小
// 音视频
{"cmd":"media","data":{"id":"...","group":"...", "content": "..."}, "event": "play"} // 播放
{"cmd":"media","data":{"id":"...","group":"...", "content": "..."}, "event": "pause"} // 暂停
{"cmd":"media","data":{"id":"...","group":"...", "content": "..."}, "event": "jump"} // 跳转
{"cmd":"media","data":{"id":"...","group":"...", "content": "..."}, "event": "cyclic"} // 循环播放
{"cmd":"media","data":{"id":"...","group":"...", "content": "..."}, "event": "mute"} // 音量
{"cmd":"media","data":{"id":"...","group":"...", "content": "..."}, "event": "unmute"} // 音量
// 图片
{"cmd":"image","data":{"id":"...","group":"...", "content": "..."}, "event": "zoom"} // 音量
{"cmd":"image","data":{"id":"...","group":"...", "content": "..."}, "event": "angle"} // 旋转
// word

*/

const (
	ParseError string = "命令解析错误"
)

// Manager 所有 websocket 信息
type Manager struct {
	ClientMapGroup   map[string]string
	Member           map[string]*member
	Group            map[string]map[string]*Client
	groupCount       uint
	clientCount      uint
	Lock             sync.Mutex
	Register         chan *Client
	UnRegister       chan *Client
	Message          chan *MessageData
	GroupMessage     chan *GroupMessageData
	BroadCastMessage chan *BroadCastMessageData
}

type ClientMapGroup struct {
	Group string
}

// Client 单个websocket 信息

type Client struct {
	Id, Group string
	Member    member
	Socket    *websocket.Conn
	Message   chan []byte
	RawData   chan []byte
}

// messageData 单个发送数据信息

type MessageData struct {
	Id, Group string
	Message   []byte
}

// groupMessageData 组广播数据信息

type GroupMessageData struct {
	Group      string
	ExcludeUid []string
	Message    []byte
}

// 广播发送数据信息

type BroadCastMessageData struct {
	Message    []byte
	ExcludeUid []string
}

type EncodeData struct {
	Cmd  string `json:"cmd"`
	Data struct {
		Event   string `json:"event"`
		Content string `json:"content"`
		Cmd     string `json:"cmd"`
	}
	Event  string `json:"event"`
	Target struct {
		Id    string `json:"id"`
		Group string `json:"group"`
	}
}

// 初始化 wsManager 管理器

var WebsocketManager = Manager{
	ClientMapGroup:   make(map[string]string),
	Member:           make(map[string]*member),
	Group:            make(map[string]map[string]*Client),
	Register:         make(chan *Client, 256),
	UnRegister:       make(chan *Client, 256),
	GroupMessage:     make(chan *GroupMessageData, 256),
	Message:          make(chan *MessageData, 256),
	BroadCastMessage: make(chan *BroadCastMessageData, 256),
	groupCount:       0,
	clientCount:      0,
}

// 从 websocket 链接直接读取数据

func (c *Client) Read() {
	defer func() {
		WebsocketManager.UnRegister <- c
		log.Printf("client [%s] disconnect", c.Id)
		if err := c.Socket.Close(); err != nil {
			log.Printf("client [%s] disconnect err: %s", c.Id, err)
		}
	}()
	for {
		messageType, message, err := c.Socket.ReadMessage()
		if err != nil || messageType == websocket.CloseMessage {
			break
		}
		log.Printf("client [%s] receive message: %s", c.Id, string(message))
		//fmt.Println("info", WebsocketManager.Info())
		var parseData EncodeData
		err = json.Unmarshal(message, &parseData)
		if err != nil {
			c.Message <- ResMsg2("", "", ParseError)
			continue
		}
		parseData.Data.Event = parseData.Event
		parseData.Data.Cmd = parseData.Cmd
		switch {
		case parseData.Cmd == "":
			c.Message <- ResMsg2("", "", ParseError)
			continue
		case parseData.Cmd == "clients":
			// c.Message <- ResMsg("客户端列表", util.SuccessCode, gin.H{"list": WebsocketManager.Members()})
			j, _ := json.Marshal(WebsocketManager.Members())
			c.Message <- ResMsg2(parseData.Cmd, parseData.Data.Event, string(j))
			continue
		default:
			targetData, _ := json.Marshal(parseData.Data)
			if len(parseData.Target.Id) > 0 {
				WebsocketManager.Send(parseData.Target.Id, targetData)
				continue
			}
			if len(parseData.Target.Group) > 0 {
				WebsocketManager.SendGroup(parseData.Target.Group, targetData, []string{c.Id})
				continue
			}
			WebsocketManager.SendAll(targetData, []string{c.Id})
		}

		// z回执
		/*c.Message <- ResMsg("发送成功", util.SuccessCode, gin.H{
			"raw_data": message,
		})*/
	}
}

// 写信息,从 channel 变量 send 中读取数据写入 websocket 链接

func (c *Client) Write() {
	defer func() {
		log.Printf("client [%s] disconnect", c.Id)
		if err := c.Socket.Close(); err != nil {
			log.Printf("client [%s] disconnect err: %s", c.Id, err)
		}
	}()

	for {
		select {
		case message, ok := <-c.Message:
			if !ok {
				// _ = c.Socket.WriteMessage(websocket.CloseMessage, []byte{})
				break
			}
			log.Printf("client [%s] write message: ---", c.Id)
			//log.Printf("client [%s] write message: %s", c.Id, string(message))

			err := c.Socket.WriteMessage(websocket.TextMessage, message)
			if err != nil {
				log.Printf("client [%s] writemessage err: %s", c.Id, err)
				break
			}
		}
	}
}

// 启动 websocket 管理器

func (manager *Manager) Start() {
	log.Printf("websocket manage start")
	for {
		select {
		// 注册
		case client := <-manager.Register:
			log.Printf("client [%s] connect", client.Id)
			log.Printf("register client [%s] to group [%s]", client.Id, client.Group)
			manager.Lock.Lock()
			if manager.Group[client.Group] == nil {
				manager.Group[client.Group] = make(map[string]*Client)
				manager.groupCount += 1
			}
			manager.Member[client.Id] = &client.Member
			manager.ClientMapGroup[client.Id] = client.Group
			manager.Group[client.Group][client.Id] = client
			manager.clientCount += 1
			manager.Lock.Unlock()

		// 注销
		case client := <-manager.UnRegister:
			log.Printf("unregister client [%s] from group [%s]", client.Id, client.Group)
			// WebsocketManager.SendAll(ResMsg("下线通知", util.Offline, manager.Member[client.Id]), []string{client.Id})
			j, _ := json.Marshal(manager.Member[client.Id])
			WebsocketManager.SendAll(ResMsg2("notify", "offline", string(j)), []string{client.Id})
			manager.Lock.Lock()
			if _, ok := manager.Group[client.Group]; ok {
				if _, ok1 := manager.Group[client.Group][client.Id]; ok1 {
					delete(manager.Group[client.Group], client.Id)
					manager.clientCount -= 1
					if len(manager.Group[client.Group]) == 0 {
						delete(manager.Group, client.Group)
						manager.groupCount -= 1
					}
				}
			}
			if _, ok := manager.ClientMapGroup[client.Id]; ok {
				delete(manager.ClientMapGroup, client.Id)
			}
			if _, ok := manager.Member[client.Id]; ok {
				delete(manager.Member, client.Id)
			}
			manager.Lock.Unlock()
		}
	}
}

// 处理单个 client 发送数据

func (manager *Manager) SendService() {
	for {
		select {
		case data := <-manager.Message:
			if groupMap, ok := manager.Group[data.Group]; ok {
				if conn, ok := groupMap[data.Id]; ok {
					conn.Message <- data.Message
				}
			}
		}
	}
}

// 处理 group 广播数据

func (manager *Manager) SendGroupService() {
	for {
		select {
		case data := <-manager.GroupMessage:
			if groupMap, ok := manager.Group[data.Group]; ok {
				for uid, conn := range groupMap {
					flag := true
					for _, excUid := range data.ExcludeUid {
						if uid == excUid {
							flag = false
							continue
						}
					}
					if flag {
						conn.Message <- data.Message
					}
				}
			}
		}
	}
}

// 处理广播数据

func (manager *Manager) SendAllService() {
	for {
		select {
		case data := <-manager.BroadCastMessage:
			for _, v := range manager.Group {
				for uid, conn := range v {
					flag := true
					for _, excUid := range data.ExcludeUid {
						if uid == excUid {
							flag = false
							continue
						}
					}
					if flag {
						conn.Message <- data.Message
					}
				}
			}
		}
	}
}

// 向指定的 client 发送数据

func (manager *Manager) Send(id string, message []byte) {
	data := &MessageData{
		Id:      id,
		Group:   manager.ClientMapGroup[id],
		Message: message,
	}
	manager.Message <- data
}

// 向指定的 Group 广播

func (manager *Manager) SendGroup(group string, message []byte, excludeUids []string) {
	data := &GroupMessageData{
		Group:      group,
		Message:    message,
		ExcludeUid: excludeUids,
	}
	manager.GroupMessage <- data
}

// 广播

func (manager *Manager) SendAll(message []byte, excludeUids []string) {
	data := &BroadCastMessageData{
		Message:    message,
		ExcludeUid: excludeUids,
	}
	manager.BroadCastMessage <- data
}

// 注册

func (manager *Manager) RegisterClient(client *Client) {
	manager.Register <- client
}

// 注销

func (manager *Manager) UnRegisterClient(client *Client) {
	manager.UnRegister <- client
}

// 当前group个数

func (manager *Manager) LenGroup() uint {
	return manager.groupCount
}

// 当前链接个数

func (manager *Manager) LenClient() uint {
	return manager.clientCount
}

// 获取wsManager 管理器信息

func (manager *Manager) Info() map[string]interface{} {
	managerInfo := make(map[string]interface{})
	managerInfo["groupLen"] = manager.LenGroup()
	managerInfo["clientLen"] = manager.LenClient()
	managerInfo["chanRegisterLen"] = len(manager.Register)
	managerInfo["chanUnregisterLen"] = len(manager.UnRegister)
	managerInfo["chanMessageLen"] = len(manager.Message)
	managerInfo["chanGroupMessageLen"] = len(manager.GroupMessage)
	managerInfo["chanBroadCastMessageLen"] = len(manager.BroadCastMessage)
	return managerInfo
}

// 获取成员列表

func (manager *Manager) Members() []interface{} {
	members := make([]interface{}, 0)
	for _, v := range manager.Member {
		members = append(members, v)
	}
	return members
}

// 测试组广播

func TestSendGroup() {
	for {
		time.Sleep(time.Second * 20)
		WebsocketManager.SendGroup("leffss", []byte("SendGroup message ----"+time.Now().Format("2006-01-02 15:04:05")), []string{})
	}
}

// 测试广播

func TestSendAll() {
	for {
		time.Sleep(time.Second * 25)
		WebsocketManager.SendAll([]byte("SendAll message ----"+time.Now().Format("2006-01-02 15:04:05")), []string{})
		fmt.Println(WebsocketManager.Info())
	}
}

// 返回消息

func ResMsg(msg string, code int, data interface{}) []byte {
	resmsg := util.ReturnResultMsgType{Description: msg, Code: code, Data: data}
	resJson, _ := json.Marshal(&resmsg)
	return resJson
}

func ResMsg2(cmd string, event string, content string) []byte {
	var parseData EncodeData
	parseData.Data.Event = event
	parseData.Data.Cmd = cmd
	// parseData.Data.Content = content
	// j, _ := json.Marshal(content)
	parseData.Data.Content = strconv.Quote(content)
	resJson, _ := json.Marshal(&parseData.Data)
	return resJson
}

type member struct {
	Id       string `json:"id"`
	Group    string `json:"group"`
	Uid      string `json:"uid"`
	Nickname string `json:"nickname"`
	Hostname string `json:"hostname"`
	Host     string `json:"host"`
}

// gin 处理 websocket handler

func (manager *Manager) WsClient(ctx *gin.Context) {
	upGrader := websocket.Upgrader{
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
		// 处理 Sec-WebSocket-Protocol Header
		Subprotocols: []string{ctx.GetHeader("Sec-WebSocket-Protocol")},
	}

	conn, err := upGrader.Upgrade(ctx.Writer, ctx.Request, nil)
	if err != nil {
		log.Printf("websocket connect error: %s", ctx.Param("channel"))
		return
	}
	if !IsPass(ctx.ClientIP()) {
		_ = conn.WriteMessage(websocket.TextMessage, ResMsg("没有打开远程权限", util.ErrorCode, nil))
		defer conn.Close()
		return
	}
	code := ctx.Query("code")
	if len(code) == 0 {
		_ = conn.WriteMessage(websocket.TextMessage, ResMsg("参数不能为空", util.ErrorCode, nil))
		defer conn.Close()
		return
	}
	decode, err := base64.StdEncoding.DecodeString(code)
	if err != nil {
		_ = conn.WriteMessage(websocket.TextMessage, ResMsg("code 错误", util.ErrorCode, nil))
		defer conn.Close()
		return
	}
	var m member
	err = json.Unmarshal(decode, &m)
	if err != nil {
		_ = conn.WriteMessage(websocket.TextMessage, ResMsg("code 错误", util.ErrorCode, nil))
		defer conn.Close()
		return
	}
	m.Host = ctx.ClientIP()
	channel := ctx.Param("channel")
	fmt.Println("channel", channel)
	id := uuid.NewString()
	m.Id = id
	m.Group = channel
	client := &Client{
		Id:      id,
		Group:   channel,
		Member:  m,
		Socket:  conn,
		Message: make(chan []byte, 1024),
	}
	manager.RegisterClient(client)
	go client.Read()
	go client.Write()
	time.Sleep(time.Duration(1) * time.Second)
	manager.Send(client.Id, ResMsg("链接成功", util.SuccessCode, gin.H{"id": id}))
	// manager.SendAll(ResMsg("上线通知", util.Online, m), []string{client.Id})
	// j,_ := json.Marshal(m)
	fmt.Println("m", m)
	j, _ := json.Marshal(m)
	manager.SendAll(ResMsg2("notify", "online", string(j)), []string{client.Id})
	//manager.SendAll(resJson, []string{})
}

// 检查白名单

func checkWhitelist(clientIp string) bool {
	fmt.Println("Whitelist", util.Whitelist)
	for _, v := range util.Whitelist {
		if v == clientIp {
			return true
		}
	}
	return false
}

// 判断是否可以远程连接

func IsPass(clientIp string) bool {
	fmt.Println("clientIp", clientIp)
	if checkWhitelist(clientIp) {
		return true
	}
	return util.RemoteControl
}

func Switch(ctx *gin.Context) {
	t := ctx.Param("type")
	// 开
	if t == "on" {
		util.RemoteControl = true
	}
	// 关
	if t == "off" {
		util.RemoteControl = false
	}
	ctx.JSON(http.StatusOK, util.ReturnResultMsgType{Code: util.SuccessCode, Description: "设置成功"})
}
